package GUI;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Vector;
 
import javax.swing.table.AbstractTableModel;
 
public class OurCustomTableModel extends AbstractTableModel{
       
        private String className;
        private ArrayList<?> container;
        private String[] columnNames;
       
        private Class clazz;
        private ArrayList<Field> fieldNames;
        private ArrayList<Method> classMethods;
        private ArrayList<Method> setters;
        private ArrayList<Method> getters;
               
        /**
         * Constructor
         *
         * @param className name of the class this model will be used for
         * @param actualColumnNames  an Array with the columnNames used for this specific model
         * @param list An ArrayList that is being used as an pointee for this model
         * @throws ClassNotFoundException
         */
        public OurCustomTableModel(String className, String[] actualColumnNames, ArrayList<?> list ) throws ClassNotFoundException, NoSuchMethodException{
                this.className = className;
                this.container = list;         
                this.columnNames = actualColumnNames;
                               
                // assign clazz to the Class type in className
                this.clazz  = Class.forName(className);
               
                // get the field names from the Class
                this.fieldNames = getClassFields();
               
                // get all class methods
                this.classMethods = getClassMethods();
               
                // set up getters
                this.getters = getSpecificClassMethods("get", classMethods);
               
                // set up setters
                this.setters = getSpecificClassMethods("set", classMethods);           
        }      
       
        private ArrayList<Field> getClassFields() {
               
                // temp list for fields
                ArrayList<Field> tempFields = new ArrayList<Field>();
               
                // get all fields from superclass (optional)
                Field[] superFields = clazz.getSuperclass().getDeclaredFields();
               
                // get all fields from this class
            Field[] fields = clazz.getDeclaredFields();
               
            // put all collected fields into temp list for fields              
            if(superFields != null) {
                for(Field field : superFields) {
                        tempFields.add(field);
                }
            }
           
            for(Field field : fields) {
                tempFields.add(field);
            }
           
            // return list to the constructor
            return tempFields;     
        }
       
        private ArrayList<Method> getClassMethods() {
                // temp list for class methods
                ArrayList<Method> tempClassMethods = new ArrayList<Method>();
                               
                // get all methods from superclass (optional)
                Method[] superMethods = clazz.getSuperclass().getDeclaredMethods();
                               
                // get all methods from this class
                Method[] methods = clazz.getDeclaredMethods();
               
                for(Method method : superMethods) {
                        if(superMethods != null) {
                                tempClassMethods.add(method);
                        }
                }
               
                for(Method method : methods) {
                        tempClassMethods.add(method);
                }
               
                // return list to the constructor
                return tempClassMethods;
        }
       
        private ArrayList<Method> getSpecificClassMethods(String filterText, ArrayList<Method> allClassMethods) {
               
                ArrayList<Method> tempSpecificClassMethods = new ArrayList<Method>();
                if(filterText != null && allClassMethods != null) {
                        for(Method method : allClassMethods) {
                                if(method.getName().contains(filterText))
                                        tempSpecificClassMethods.add(method);                                  
                        }
                }
               
                // return list to constructor
                return tempSpecificClassMethods;
        }

       
        // actual table methods
        //@Override
        
        public int getColumnCount() {
                return columnNames.length;
        }
 
        //@Override
        public int getRowCount() {
                return container.size();
        }
 
        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
               	
        		String getFieldNameMethod = null;
        		String fieldName = null;
        		
                Object o = container.get(rowIndex);
                if(columnIndex <= columnNames.length) {
                	fieldName = fieldNames.get(columnIndex).getName();                              
                    getFieldNameMethod = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                }
                
               
                int index = 0;
                
                if(fieldName != null && getFieldNameMethod != null) {
                	for(Method method : getters)
                	{		
                        if(method.getName().equalsIgnoreCase(getFieldNameMethod))
                        {
                                Method getMethod = null;
                                try {
                                        getMethod = o.getClass().getMethod(getFieldNameMethod, null);
                                       
                                } catch (NoSuchMethodException | SecurityException e) {
                                        e.printStackTrace();
                                }
                                try {                                  
                                        return getMethod.invoke(o, null);
                                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                                	e.printStackTrace();
                                }
                        	}
                	}      
                }
                
                return null;
        }
               
        @Override
        public String getColumnName(int Index) {
                return columnNames[Index];
        }
       
        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
                return false;
        }      
}